/**
 * 建造者模式：将复杂对象的构建和其表示分离，使得相同的构建过程可以产生不同的表示。
 * 以下情形可以考虑使用建造者模式：
 * 1.对象的创建复杂，但是其各个部分的子对象创建算法一定。
 * 2.需求变化大，构造复杂对象的子对象经常变化，但将其组合在一起的算法相对稳定。
 * 建造者模式的优点：
 * 1.将对象的创建和表示分离，客户端不需要了解具体的构建细节。
 * 2.加新的产品对象时，只需要增加其具体的建造类即可，不需要修改原来的代码，扩展方便。
 * 产品之间差异性大，内部变化较大、较复杂时不建议使用建造者模式。
 */
#pragma once

#include <iostream>
#include <string>
#include <memory>

namespace builder
{
//具体的产品类
class Car
{
public:
    void setEngine(const std::string& engine) {
        m_engine = engine;
    }
    const std::string& engine() const {
        return m_engine;
    }

    void setSeats(const int seats) {
        m_seats = seats;
    }
    const int seats() const {
        return m_seats;
    }

    void setComputer(const bool value) {
        m_computer = value;
    }
    const bool computer() const {
        return m_computer;
    }

    void setGPS(const bool value) {
        m_GPS = value;
    }
    const bool GPS() const {
        return m_GPS;
    }

    friend std::ostream& operator<< (std::ostream& out, const Car& car) {
        out << "Car(" << "engine:" << car.engine() << ", seats:" << car.seats()
            << ", computer:" << car.computer() << ", GPS:" << car.GPS() << ")";
        return out;
    }
private:
    std::string m_engine;
    int         m_seats;
    bool        m_computer;
    bool        m_GPS;
};

//抽象建造类，提供建造接口。
class CarBuilder
{
public:
    CarBuilder() {
        reset();
    }
    ~CarBuilder() {
        delete m_car;
        m_car = nullptr;
    }
    virtual void reset() {
        m_car = new Car();
    }
    virtual Car* car() {
        auto car = m_car;
        reset();
        return car;
    }
    virtual void setEngine() = 0;
    virtual void setSeats() = 0;
    virtual void setComputer() = 0;
    virtual void setGPS() = 0;

protected:
    Car* m_car;
};

class SedanBuilder : public CarBuilder
{
public:
    SedanBuilder() : CarBuilder() {}
    void setEngine() override {
        m_car->setEngine("Sedan Engine");
    }
    void setSeats() override {
        m_car->setSeats(5);
    }
    void setComputer() override {
        m_car->setComputer(true);
    }
    void setGPS() override {
        m_car->setGPS(true);
    }
};

class BusBuilder : public CarBuilder
{
public:
    BusBuilder() : CarBuilder() {}
    void setEngine() override {
        m_car->setEngine("Bus Engine");
    }
    void setSeats() override {
        m_car->setSeats(20);
    }
    void setComputer() override {
        m_car->setComputer(false);
    }
    void setGPS() override {
        m_car->setGPS(true);
    }
};

//Director类，负责管理实例创建的依赖关系，指挥构建者类创建实例,不是必须，也可以直接在客户端创建
class Director
{
public:
    Director(CarBuilder* builder) : m_builder(builder) {}
    void setBuilder(CarBuilder* builder) {
        m_builder = builder;
    }
    void construct() {
        m_builder->setEngine();
        m_builder->setSeats();
        m_builder->setComputer();
        m_builder->setGPS();
    }

private:
    CarBuilder* m_builder;
};

void ClientCode() {
    std::unique_ptr<CarBuilder> sedanBuilder(new SedanBuilder);
    std::unique_ptr<CarBuilder> busBuilder(new BusBuilder);
    std::unique_ptr<Director> director(new Director(sedanBuilder.get()));
    director->construct();
    director->setBuilder(busBuilder.get());
    director->construct();

    Car* sedan = sedanBuilder->car();
    Car* bus = busBuilder->car();

    std::cout << *sedan << std::endl;
    std::cout << *bus << std::endl;
}
} //namespace builder